package com.qunar.mina.app.service.impl;

import java.io.FileNotFoundException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Iterator;
import java.util.List;

import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.FuzzyQuery;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.MultiSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.WildcardQuery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.wltea.analyzer.lucene.IKQueryParser;

import com.qunar.mina.app.config.DirectoryConfig;
import com.qunar.mina.app.model.SearcherModel;
import com.qunar.mina.app.service.SearcherService;
import com.qunar.mina.app.utils.JdbcUtils;
import com.qunar.mina.app.utils.WriterUtils;
import com.qunar.wireless.ugc.qcfclient.dto.Address;
import com.qunar.wireless.ugc.qcfclient.dto.Auditor;
import com.qunar.wireless.ugc.qcfclient.dto.Pic;
import com.qunar.wireless.ugc.qcfclient.dto.QueryResult;
import com.qunar.wireless.ugc.qcfclient.dto.User;

public class SearcherServiceBean<T> implements SearcherService {
	private final Logger logger = LoggerFactory.getLogger(SearcherServiceBean.class);

	private void addPicDocs(IndexWriter fsIndexWriter) {
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			conn = JdbcUtils.getConnection();
			String sql = "select pic_id, user_id, auditor_id, url, description, create_time, audit_time, activity_name, illegality_status from pic";
			pstmt = conn.prepareStatement(sql);
			rs = pstmt.executeQuery();
			long begin = System.currentTimeMillis();
			// 对user表建立索引
			while (rs.next()) {
				Pic pic = new Pic();
				pic.setPicId(rs.getLong("pic_id"));
				pic.setUserId(rs.getLong("user_id"));
				pic.setUrl(rs.getString("url"));
				pic.setDescription(rs.getString("description"));
				pic.setAuditorId(rs.getInt("auditor_id"));
				pic.setCreateTime(rs.getDate("create_time"));
				pic.setAuditTime(rs.getDate("audit_time"));
				pic.setActivityName(rs.getString("activity_name"));
				pic.setIllegalityStatus(rs.getInt("illegality_status"));
				Document doc = WriterUtils.pic2Document(pic);
				fsIndexWriter.addDocument(doc);
			}
			fsIndexWriter.commit();
			long end = System.currentTimeMillis();
			logger.info("创建索引库耗时:" + (end - begin) + "ms");
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		} finally {
			JdbcUtils.release(conn, pstmt, rs);
		}
	}

	private void addAuditorDocs(IndexWriter fsIndexWriter) {
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			conn = JdbcUtils.getConnection();
			String sql = "select auditor_id, name, rtxAccount from auditor";
			pstmt = conn.prepareStatement(sql);
			rs = pstmt.executeQuery();
			long begin = System.currentTimeMillis();
			// 对user表建立索引
			while (rs.next()) {
				Auditor auditor = new Auditor();
				auditor.setAuditorId(rs.getInt("auditor_id"));
				auditor.setName(rs.getString("name"));
				auditor.setRtxAccount(rs.getString("rtxAccount"));
				Document doc = WriterUtils.auditor2Document(auditor);
				fsIndexWriter.addDocument(doc);
			}
			fsIndexWriter.commit();
			long end = System.currentTimeMillis();
			logger.info("创建索引库耗时:" + (end - begin) + "ms");
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		} finally {
			JdbcUtils.release(conn, pstmt, rs);
		}
	}

	private void addUserDocs(IndexWriter fsIndexWriter) {
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			conn = JdbcUtils.getConnection();
			String sql = "select user_id, username from user";
			pstmt = conn.prepareStatement(sql);
			rs = pstmt.executeQuery();
			long begin = System.currentTimeMillis();
			// 对user表建立索引
			while (rs.next()) {
				User user = new User();
				user.setUserId(rs.getLong("user_id"));
				user.setUsername(rs.getString("username"));
				Document doc = WriterUtils.user2Document(user);
				fsIndexWriter.addDocument(doc);
			}
			fsIndexWriter.commit();
			long end = System.currentTimeMillis();
			logger.info("创建索引库耗时:" + (end - begin) + "ms");
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		} finally {
			JdbcUtils.release(conn, pstmt, rs);
		}
	}

	private void addAddressDocs(IndexWriter fsIndexWriter) {
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			conn = JdbcUtils.getConnection();
			String sql = "select address_id, name, detail, city_id, is_valid, is_shield from address";
			pstmt = conn.prepareStatement(sql);
			rs = pstmt.executeQuery();
			long begin = System.currentTimeMillis();
			// 对address表建立索引
			while (rs.next()) {
				Address address = new Address();
				address.setAddressId(rs.getLong("address_id"));
				address.setName(rs.getString("name"));
				address.setDetail(rs.getString("detail"));
				address.setCityId(rs.getInt("city_id"));
				address.setIsValid(rs.getInt("is_valid"));
				address.setIsShield(rs.getInt("is_shield"));
				Document doc = WriterUtils.address2Document(address);
				fsIndexWriter.addDocument(doc);
			}
			fsIndexWriter.commit();
			long end = System.currentTimeMillis();
			logger.info("创建索引库耗时:" + (end - begin) + "ms");
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		} finally {
			JdbcUtils.release(conn, pstmt, rs);
		}
	}

	/**
	 * 对address表执行索引文件创建
	 */
	@Override
	public void createIndex() {
		try {
			IndexWriter fsAddressWriter = WriterUtils.getFsAddressWriter();
			fsAddressWriter.deleteAll();
			fsAddressWriter.commit();

			IndexWriter fsUserWriter = WriterUtils.getUserWriter();
			fsUserWriter.deleteAll();
			fsUserWriter.commit();

			IndexWriter fsAuditorWriter = WriterUtils.getAuditorWriter();
			fsAuditorWriter.deleteAll();
			fsAuditorWriter.commit();

			IndexWriter fsPicWriter = WriterUtils.getPicWriter();
			fsPicWriter.deleteAll();
			fsPicWriter.commit();

			addAddressDocs(fsAddressWriter);
			addUserDocs(fsUserWriter);
			addAuditorDocs(fsAuditorWriter);
			addPicDocs(fsPicWriter);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		}
	}

	/**
	 * 索引查询
	 * 
	 * @return
	 */
	@Override
	public QueryResult searcher(String keyword, Integer firstResult, Integer maxResult, String searcherName, String... fields) {
		if (maxResult > 50) {
			throw new IllegalArgumentException("maxResult is too larger.");
		}

		if (fields.length == 0) {
			throw new IllegalArgumentException("query field must not null.");
		}

		IndexSearcher searcher = null;
		MultiSearcher multiSearcher = null;
		Query query = null;
		try {

			if ("address".equals(searcherName)) {
				searcher = new IndexSearcher(DirectoryConfig.getFsAddressDirectory());
			} 
			if ("pic".equals(searcherName)) {
				searcher = new IndexSearcher(DirectoryConfig.getFSPicDirectory());
			}

			multiSearcher = SearcherModel.getParallelMultiSearcher(searcher);

			query = IKQueryParser.parseMultiField(fields, keyword);

			long begin = System.currentTimeMillis();
			TopDocs topDocs = multiSearcher.search(query, 1000);
			long end = System.currentTimeMillis();
			QueryResult qr = SearcherModel.getQueryResult(firstResult, maxResult, multiSearcher, topDocs);
			logger.info("查询" + maxResult + "条记录共耗时：" + (end - begin) + "ms");

			return qr;
		} catch (FileNotFoundException e) {
			logger.info("索引库进行物理删除后，第一次检索会找不到索引" + e.getMessage());
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		} finally {
			SearcherModel.closeSearcher(searcher, multiSearcher);
		}
		return new QueryResult();
	}
	
	/**
	 * 通配符查询
	 */
	@Override
	public QueryResult wildcardSearcher(String keyword, Integer firstResult, Integer maxResult, String field) {
		if(maxResult > 50) {
			throw new IllegalArgumentException("maxResult is too larger.");
		}
		
		if(field == null || "".equals(field)) {
			throw new IllegalArgumentException("query field must not null.");
		}
		
		IndexSearcher searcher = null;
		Query query = null;
		try {
			searcher = new IndexSearcher(DirectoryConfig.getFSUserDirectory());
			query = new WildcardQuery(new Term(field, keyword));

			long begin = System.currentTimeMillis();
			TopDocs topDocs = searcher.search(query, 1000);
			long end = System.currentTimeMillis();
			QueryResult qr = SearcherModel.getQueryResult(firstResult, maxResult, searcher, topDocs);
			
			logger.info("通配符查询" + maxResult + "条记录共耗时：" + (end - begin) + "ms");

			return qr;
		} catch (FileNotFoundException e) {
			logger.info("索引库进行物理删除后，第一次检索会找不到索引" + e.getMessage());
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		} finally {
			SearcherModel.closeSearcher(searcher);
		}
		return new QueryResult();
	}
	

	/**
	 * 模糊匹配查询
	 */
	@Override
	public QueryResult fuzzySearcher(String keyword, Integer firstResult, Integer maxResult, String field) {
		
		if(maxResult > 50) {
			throw new IllegalArgumentException("maxResult is too larger.");
		}
		
		if(field == null || "".equals(field)) {
			throw new IllegalArgumentException("query field must not null.");
		}
		
		IndexSearcher searcher = null;
		Query query = null;
		try {
			searcher = new IndexSearcher(DirectoryConfig.getFSUserDirectory());
			query = new FuzzyQuery(new Term(field, keyword));

			long begin = System.currentTimeMillis();
			TopDocs topDocs = searcher.search(query, 1000);
			long end = System.currentTimeMillis();
			QueryResult qr = SearcherModel.getQueryResult(firstResult, maxResult, searcher, topDocs);
			
			logger.info("模糊查询" + maxResult + "条记录共耗时：" + (end - begin) + "ms");

			return qr;
		} catch (FileNotFoundException e) {
			logger.info("索引库进行物理删除后，第一次检索会找不到索引" + e.getMessage());
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		} finally {
			SearcherModel.closeSearcher(searcher);
		}
		return new QueryResult();
		
	}

	@Override
	public QueryResult searcherScan(String keyword, Integer firstResult, Integer maxResult, String searcherName, String... fields) {
		if (maxResult > 50) {
			throw new IllegalArgumentException("maxResult is too larger.");
		}

		if (fields.length == 0) {
			throw new IllegalArgumentException("query field must not null.");
		}
		IndexSearcher searcher = null;
		Query query = null;
		try {

			if ("user".equals(searcherName)) {
				searcher = new IndexSearcher(DirectoryConfig.getFSUserDirectory());
			} 
			if ("auditor".equals(searcherName)) {
				searcher = new IndexSearcher(DirectoryConfig.getFSAuditorDirectory());
			}

			query = new TermQuery(new Term(fields[0], keyword));

			long begin = System.currentTimeMillis();
			TopDocs topDocs = searcher.search(query, 1000);
			long end = System.currentTimeMillis();
			QueryResult qr = SearcherModel.getQueryResult(firstResult, maxResult, searcher, topDocs);
			logger.info("查询" + maxResult + "条记录共耗时：" + (end - begin) + "ms");

			return qr;
		} catch (FileNotFoundException e) {
			logger.info("索引库进行物理删除后，第一次检索会找不到索引" + e.getMessage());
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		} finally {
			SearcherModel.closeSearcher(searcher);
		}
		return new QueryResult();

	}

	/**
	 * 批量创建索引
	 */
	@Override
	public void batchaddIndex(final List<Address> list) {

		if (list.size() > 200) {
			return;
		}

		IndexWriter fsIndexWriter = null;
		try {
			fsIndexWriter = WriterUtils.getFsAddressWriter();
			long start = System.currentTimeMillis();
			
			for (Iterator iterator = list.iterator(); iterator.hasNext();) {
				Address addr = (Address) iterator.next();
				Document doc = WriterUtils.address2Document(addr);
				fsIndexWriter.addDocument(doc);
			}
			fsIndexWriter.commit();
			long end = System.currentTimeMillis();
			logger.info("批量添加索引成功,共耗时：" + (end - start) + "ms");
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		}
	}

	/**
	 * 新增索引到索引文件中
	 */
	@Override
	public void addIndex(final Address address, final String writerName) {

		Document doc = WriterUtils.address2Document(address);
		IndexWriter fsIndexWriter = null;
		try {
			if ("address".equals(writerName)) {
				fsIndexWriter = WriterUtils.getFsAddressWriter();
			} 
			if ("pic".equals(writerName)) {
				fsIndexWriter = WriterUtils.getPicWriter();
			}
			long start = System.currentTimeMillis();
			fsIndexWriter.addDocument(doc);
			fsIndexWriter.commit();
			long end = System.currentTimeMillis();
			logger.info("添加索引成功,共耗时：" + (end - start) + "ms");
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		}

	}

	/**
	 * 删除索引从索引文件中
	 * 
	 * @param term
	 */
	@Override
	public void deleteIndex(final Term term, final String writerName) {

		IndexWriter fsWriter = null;
		try {
			if ("address".equals(writerName)) {
				fsWriter = WriterUtils.getFsAddressWriter();
			} 
			if ("pic".equals(writerName)) {
				fsWriter = WriterUtils.getPicWriter();
			}
			long start = System.currentTimeMillis();
			fsWriter.deleteDocuments(term);
			fsWriter.commit();
			long end = System.currentTimeMillis();
			logger.info("删除Address索引成功,共耗时：" + (end - start) + "ms");
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		}

	}

	


}
